home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / HAPN.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  12KB  |  518 lines

  1. /*  Driver for HAPN-1 8273 card
  2.  *  Jon Bloom, KE3Z; adapted from KA9Q's PC-100 driver
  3.  *  Modified Rx interrupt routine to prevent lockup
  4.  *  John Tanner VK2ZXQ 6th Feb 1988
  5.  *  Adapted back into 871225.9 by KA9Q 15 Feb 1988
  6.  */
  7. #include <stdio.h>
  8. #include <dos.h>
  9. #ifdef    ANSIPROTO
  10. #include <stdarg.h>
  11. #endif
  12. #include "global.h"
  13. #include "timer.h"
  14. #include "mbuf.h"
  15. #include "iface.h"
  16. #include "hapn.h"
  17. #include "ax25.h"
  18. #include "trace.h"
  19. #include "pc.h"
  20. #include "proc.h"
  21.  
  22. static void cmd_8273 __ARGS((int16 base,int cmd,int np,...));
  23. static int hapn_init __ARGS((struct hapn *hp));
  24. static int hapn_raw __ARGS((struct iface *iface,struct mbuf *bp));
  25. static int hapn_stop __ARGS((struct iface *iface));
  26. static int hcdchk __ARGS((int16 base));
  27. static void hrxint __ARGS((struct hapn *hp));
  28. static void hrxgo __ARGS((struct hapn *hp));
  29. static void htxint __ARGS((void *p));
  30.  
  31. static struct hapn Hapn[NHAPN];
  32. static INTERRUPT (*H_handle[])() = { ha0vec };
  33. static int16 Nhapn;
  34.  
  35. /*  send command to the 8273
  36.  *  "base" = base port of 8273
  37.  *  "cmd"  = command byte
  38.  *  "np"   = number of parameter bytes
  39.  *  "p1"   = first parameter (parameters are int)
  40.  */
  41. #ifdef    ANSIPROTO
  42. static void
  43. cmd_8273(int16 base, int cmd, int np, ...)
  44. {
  45.     int p;
  46.     va_list ap;
  47.  
  48.     while(inportb(base+STA) & CBSY)
  49.         ;
  50.     outportb(base+CMD, cmd);
  51.  
  52.     va_start(ap,np);
  53.     while(np--){
  54.         while(inportb(base+STA) & CPBF)
  55.             ;
  56.         p = va_arg(ap,int);
  57.         outportb(base+PAR, p);
  58.     }
  59.     va_end(ap);
  60. }
  61. #else
  62. /*VARARGS3*/
  63. static void
  64. cmd_8273(base, cmd, np, p1)
  65. int16 base;
  66. int cmd, np, p1;
  67. {
  68.     int *p;
  69.  
  70.     while(inportb(base+STA) & CBSY)
  71.         ;
  72.     outportb(base+CMD, cmd);
  73.     p = &p1;
  74.     while(np--){
  75.         while(inportb(base+STA) & CPBF)
  76.             ;
  77.         outportb(base+PAR, *p++);
  78.     }
  79. }
  80. #endif
  81. /*  Start receiver of 8273 */
  82. static void
  83. hrxgo(hp)
  84. register struct hapn *hp;
  85. {
  86.     cmd_8273(hp->base, GENERAL_RX, 2, hp->bufsiz & 0xff, hp->bufsiz >> 8);
  87. }
  88.  
  89. /*  Interrupt service function.  Entered with hapn index
  90.  *  The "flag" variable is used in this routine to indicate a
  91.  *  valid TX or RX interrupt. If an invalid interrupt is detected
  92.  *  the 8273 is reset.
  93.  */
  94. void
  95. haint(dev)
  96. int dev;
  97. {
  98.     register struct hapn *hp;
  99.     register int16 base;
  100.     char flag = 0;
  101.  
  102.     hp = &Hapn[dev];
  103.     base = hp->base;
  104.  
  105.     /*  Check for TX interrupt  */
  106.     if(inportb(base+STA) & TXINT){
  107.         flag = 1;    /* Valid interrupt, set flag */
  108.         htxint(hp);
  109.     }
  110.     /*  Check for RX interrupt  */
  111.     if(inportb(base+STA) & RXINT){
  112.         flag = 1;    /* Valid interrupt, set flag */
  113.         hrxint(hp);
  114.     }
  115.     /* Check for unknown interrupt  */
  116.     if(!flag){
  117.         hp->badint++;    /* Increment error counter */
  118.         hapn_init(hp);    /* Reinitialise the 8273 */
  119.     }
  120. }
  121. /*  RX interrupt service
  122.  *  if status register bit "RXIRA" is set, interrupt is final,
  123.  *  otherwise, interrupt is data request
  124.  */
  125. static void
  126. hrxint(hp)
  127. register struct hapn *hp;
  128. {
  129.     register struct mbuf *bp;
  130.     register int16 base;
  131.     unsigned char results[10];
  132.     struct phdr *phdr;
  133.  
  134.     hp->rxints++;
  135.     base = hp->base;
  136.  
  137.     if(inportb(base+STA) & RXIRA){
  138.         /* RX result interrupt
  139.          * If the result is a good frame 3 bytes need to be read
  140.          * If an error has occurred only one byte need to be read
  141.          */
  142.  
  143.         /* Read first result byte and test for good data */
  144.         if((results[0]=(inportb(base + RXI))) == 0xe0){
  145.             /* Good result; read two more result bytes */
  146.             while((inportb(base + STA) & RXIRA) == 0)
  147.                 ;
  148.             /* Read second result byte */
  149.             results[1] = inportb(base + RXI);
  150.             /* Wait for third result byte  */
  151.             while((inportb(base + STA) & RXIRA) == 0)
  152.                 ;  
  153.             results[2] = inportb(base + RXI);/* Read it */
  154.  
  155.             /* Since this frame is ok put it on the queue */
  156.             bp = alloc_mbuf(sizeof(struct phdr));
  157.             bp->cnt = sizeof(struct phdr);
  158.             phdr = (struct phdr *)bp->data;
  159.             phdr->iface = hp->iface;
  160.             phdr->type = TYPE_AX25;
  161.             bp->next = hp->rcvbuf;
  162.             hp->rcvbuf = NULLBUF;
  163.             enqueue(&Hopper, bp);
  164.             psignal(&Hopper,1);
  165.             hp->rframes++;
  166.         } else {
  167.             /* Error termination
  168.              * Parse RIC and act accordingly
  169.              * Only one result byte returned on error
  170.              */
  171.             switch(results[0]){
  172.             case CRCERR:
  173.                 hp->crcerr++;
  174.                 break;
  175.             case ABORT_DET:
  176.                 hp->aborts++;
  177.                 break;
  178.             case DMA_OVRN:
  179.                 hp->dmaorun++;
  180.                 break;
  181.             case MEM_OVFL:
  182.                 hp->toobig++;
  183.                 break;
  184.             case CD_LOSS:
  185.                 hp->cdloss++;
  186.                 hapn_init(hp);    /* 8273 reset on cd error */
  187.                 break;
  188.             case RX_ORUN:
  189.                 hp->rxorun++;
  190.                 break;
  191.             }
  192.             /* Throw rx buffer contents away to start over */
  193.             hp->rcp = hp->rcvbuf->data;
  194.             hp->rcvbuf->cnt = 0;
  195.         }
  196.         /* Restart the receiver */
  197.         cmd_8273(base,RX_DISABLE,0);
  198.         hrxgo(hp);
  199.     } else {
  200.         /* RX data interrupt; allocate new rx buffer if none present */
  201.         if((bp = hp->rcvbuf) == NULLBUF){
  202.             bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  203.             if(bp == NULLBUF){
  204.                 /* No memory available */
  205.                 hp->nomem++;
  206.                 cmd_8273(base, RX_DISABLE, 0);
  207.                 hrxgo(hp);
  208.                 return;
  209.             }
  210.             /* Init buffer pointer */
  211.             hp->rcp = hp->rcvbuf->data;
  212.         }
  213.         /*  Barf if rx data is more than buffer can hold (should never
  214.          *  happen since 8273 is also counting bytes).
  215.          */
  216.         if(bp->cnt++ >= hp->bufsiz){
  217.             hp->toobig++;
  218.             cmd_8273(base, RX_DISABLE, 0);
  219.             hrxgo(hp);
  220.             free_p(bp);
  221.             hp->rcvbuf = NULLBUF;
  222.             return;
  223.         }
  224.         /* Store the received byte */
  225.         *hp->rcp++ = inportb(base+RXD);
  226.     }
  227. }
  228.  
  229. /*  test for busy channel (CD active)
  230.  *  returns TRUE if channel busy
  231.  */
  232. static int
  233. hcdchk(base)
  234. int16 base;
  235. {
  236.     char isav;
  237.  
  238.     isav = dirps();
  239.     cmd_8273(base, READ_A, 0);
  240.     while(!(inportb(base+STA) & CRBF))
  241.         ;
  242.     restore(isav);
  243.     return((inportb(base+RES) & CD) != 0);
  244. }
  245.  
  246. /*  TX interrupt service
  247.  *  if status register bit "TXIRA" is set, interrupt is final,
  248.  *  otherwise, interrupt is data request
  249.  */
  250. static void
  251. htxint(p)
  252. void *p;
  253. {
  254.     register struct hapn *hp;
  255.     char isav;
  256.     register int16 base;
  257.     int16 len;
  258.     char c;
  259.  
  260.     hp = (struct hapn *)p;
  261.     isav = dirps();
  262.     hp->txints++;
  263.     base = hp->base;
  264.  
  265.     c = 0;
  266.     if(inportb(base+STA) & TXIRA){        /* TX result interupt */
  267.         hp->tstate = IDLE;
  268.         free_p(hp->sndbuf);
  269.         hp->sndbuf = NULLBUF;
  270.  
  271.         /*  Read result  */
  272.         while((inportb(base+STA) & (TXINT | TXIRA)) != (TXINT | TXIRA))
  273.             ;
  274.         c = inportb(base+TXI);
  275.  
  276.         /*  Test for tx abort  */
  277.         switch(c & 0x1f){
  278.         case DMA_URUN:
  279.             hp->t_urun++;
  280.             break;
  281.         case CTS_LOSS:
  282.             hp->ctsloss++;
  283.             break;
  284.         case ABORT_CMPLT:
  285.             hp->taborts++;
  286.             break;
  287.         }
  288.     }
  289.     switch(hp->tstate){
  290.     case IDLE:    /*  See if a buffer is ready to be sent  */
  291.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
  292.             break;
  293.  
  294.     case DEFER:    /*  Busy-channel check  */
  295.         if(hp->mode == CSMA && (c & 0x1f) != EARLY_TXI){
  296.             if(hcdchk(base)){
  297.                 hp->tstate = DEFER;
  298.                 start_timer(&hp->defer);
  299.                 break;
  300.             }
  301.         }
  302.         /*  Start transmitter  */
  303.         stop_timer(&hp->defer);
  304.         len = len_mbuf(hp->sndbuf);
  305.         cmd_8273(base, TX_FRAME, 2, len & 0xff, len >> 8);
  306.         hp->tstate = ACTIVE;
  307.         hp->tframes++;
  308.         break;
  309.     case ACTIVE:    /*  Get next byte to send  */
  310.         if(pullup(&hp->sndbuf, &c, 1) != 1){
  311.             cmd_8273(base, ABORT_TXF, 0);
  312.             hp->tstate = IDLE;
  313.         } else
  314.             outportb(base+TXD, c);
  315.         break;
  316.     }
  317.     restore(isav);
  318. }
  319.  
  320. /*  Attach a HAPN adaptor to the system
  321.  *  argv[0]:  hardware type, must be "hapn"
  322.  *  argv[1]:  I/O address, e.g. "0x310"
  323.  *  argv[2]:  vector, e.g. "2"
  324.  *  argv[3]:  mode, must be "ax25"
  325.  *  argv[4]:  interface name, e.g. "ha0"
  326.  *  argv[5]:  rx packet buffer size in bytes
  327.  *  argv[6]:  maximum transmission unit in bytes
  328.  *  argv[7]:  channel-access mechanism, "csma" or "full"
  329.  */
  330. int
  331. hapn_attach(argc, argv,p)
  332. int argc;
  333. char *argv[];
  334. void *p;
  335. {
  336.     register struct iface *if_h;
  337.     struct hapn *hp;
  338.     int dev, i;
  339.     char isav;
  340.     static struct {
  341.         char *str;
  342.         char type;
  343.     } ch_access [] = { "csma", 0, "full", 1 };
  344.  
  345.     if(Nhapn >= NHAPN){
  346.         printf("Too many HAPN adaptors\n");
  347.         return -1;
  348.     }
  349.     if(if_lookup(argv[4]) != NULLIF){
  350.         printf("Interface %s already exists\n",argv[4]);
  351.         return -1;
  352.     }
  353.     dev = Nhapn++;
  354.     hp = &Hapn[dev];
  355.  
  356.     /*  Initialize hardware constants */
  357.     hp->base = htoi(argv[1]);
  358.     hp->vec = htoi(argv[2]);
  359.  
  360.     /*  Save original interrupt vector  */
  361.     hp->oldvec = getirq(Hapn[dev].vec);
  362.  
  363.     /*  Set new interrupt vector  */
  364.     setirq(hp->vec, H_handle[dev]);
  365.  
  366.     /*  Create new interface structure  */
  367.     if_h = (struct iface *) calloc(1,sizeof(struct iface));
  368.     hp->iface = if_h;
  369.  
  370.     /*  Fill interface structure  */
  371.     if_h->name = strdup(argv[4]);
  372.     if_h->mtu = atoi(argv[6]);
  373.     if_h->dev = dev;
  374.     if_h->stop = hapn_stop;
  375.     if_h->output = ax_output;
  376.     if_h->raw = hapn_raw;
  377.  
  378.     if(strcmp(argv[3], "ax25")){
  379.         printf("Mode %s unknown for interface %s\n", argv[3], argv[4]);
  380.         free(if_h->name);
  381.         free((char *) if_h);
  382.         return -1;
  383.     }
  384.     axarp();
  385.     if(Mycall.call[0] == '\0'){
  386.         printf("set mycall first\n");
  387.         free(if_h->name);
  388.         free((char *) if_h);
  389.         return -1;
  390.     }
  391.     if_h->send = ax_send;
  392.     if(if_h->hwaddr == NULLCHAR)
  393.         if_h->hwaddr = malloc(sizeof(Mycall));
  394.     memcpy(if_h->hwaddr,(char *)&Mycall,sizeof(Mycall));
  395.     /*  Link the interface into the interface list  */
  396.     if_h->next = Ifaces;
  397.     Ifaces = if_h;
  398.  
  399.     /*  Fill the local data structure  */
  400.     hp->bufsiz = atoi(argv[5]);
  401.     for(i = 0; i < (sizeof ch_access / sizeof ch_access[0]); i++)
  402.         if(!strcmp(argv[7], ch_access[i].str))
  403.             hp->mode = ch_access[i].type;
  404.  
  405.     /*  Initialize the hardware  */
  406.     isav = dirps();
  407.     hapn_init(hp);
  408.  
  409.     /* Initialize the defer timer */
  410.     hp->defer.start = 1;
  411.     hp->defer.func = htxint;
  412.     hp->defer.arg = hp;
  413.  
  414.     /*  Enable the interrupt  */
  415.     maskon(hp->vec);
  416.  
  417.     restore(isav);
  418.     return 0;
  419. }
  420.  
  421. /*  initialize the HAPN adaptor */
  422. static int
  423. hapn_init(hp)
  424. register struct hapn *hp;
  425. {
  426.     register int16 base;
  427.     char isav;
  428.  
  429.     isav = dirps();
  430.     base = hp->base;
  431.  
  432.     /*  Reset the 8273 */
  433.     outportb(base+RST, 1);
  434.     outportb(base+RST, 0);
  435.     inportb(base+TXI);        /* Clear any old IR contents */
  436.     inportb(base+RXI);
  437.  
  438.     /*  Select the operating modes  */
  439.     cmd_8273(base, SET_XFER, 1, 1);
  440.     cmd_8273(base, SET_MODE, 1, HDLC | EARLY | PREFRM | FLG_STM);
  441.     cmd_8273(base, SET_SERIAL, 1, NRZI);
  442.     cmd_8273(base, SET_B, 1, IRQ_ENB | RTS);
  443.     cmd_8273(base, RST_B, 1, 0xff ^ RTS);
  444.     hrxgo(hp);
  445.     restore(isav);
  446.     return 0;
  447. }
  448.  
  449. /*  shut down the HAPN adaptor */
  450. static int
  451. hapn_stop(iface)
  452. struct iface *iface;
  453. {
  454.     int16 dev;
  455.     int16 base;
  456.     struct hapn *hp;
  457.  
  458.     dev = iface->dev;
  459.     hp = &Hapn[dev];
  460.     base = hp->base;
  461.  
  462.     /*  Mask off interrupt input  */
  463.     maskoff(hp->vec);
  464.  
  465.     /*  Restore original interrupt vector  */
  466.     setirq(hp->vec,hp->oldvec);
  467.  
  468.     /*  Reset the 8273  */
  469.     outportb(base+RST, 1);
  470.     outportb(base+RST, 0);
  471.     return 0;
  472. }
  473.  
  474. /* Display adaptor statistics */
  475. int
  476. dohapnstat(argc,argv,p)
  477. int argc;
  478. char *argv[];
  479. void *p;
  480. {
  481.     struct hapn *hp;
  482.     int i;
  483.  
  484.     if(Nhapn == 0){
  485.         printf("No HAPN adaptor attached\n");
  486.         return 1;
  487.     }
  488.     for(i = 0; i < Nhapn; i++){
  489.         hp = &Hapn[i];
  490.         printf("HAPN %d:   rxints: %ld   txints: %ld   badint: %-5d\r\n", i,
  491.          hp->rxints,hp->txints,hp->badint);
  492.         printf(" receive  - frames:  %-5d  crcerrs: %-5d  aborts: %-5d  dmaorun: %-5d\r\n",
  493.          hp->rframes,hp->crcerr, hp->aborts, hp->dmaorun);
  494.         printf("          - toobig:  %-5d  dcdloss: %-5d  rxorun: %-5d\r\n",
  495.          hp->toobig,hp->cdloss,hp->rxorun);
  496.         printf(" transmit - frames:  %-5d  aborts : %-5d  uruns : %-5d  ctsloss: %-5d\r\n",
  497.          hp->tframes,hp->taborts, hp->t_urun, hp->ctsloss);
  498.     }
  499.     return 0;
  500. }
  501.  
  502. /* Send raw packet on HAPN interface */
  503. static int
  504. hapn_raw(iface,bp)
  505. struct iface *iface;
  506. struct mbuf *bp;
  507. {
  508.     struct hapn *hp;
  509.  
  510.     hp = &Hapn[iface->dev];
  511.     enqueue(&hp->sndq, bp);
  512.  
  513.     /*  See if anything being transmitted  */
  514.     if(hp->tstate == IDLE)
  515.         htxint(hp);
  516.     return 0;
  517. }
  518.